package org.jugile.web2;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.jugile.app.domain.Domain;
import org.jugile.util.Jugile;
import org.jugile.util.Props;
import org.jugile.util.Timer;


public class MiniServlet extends HttpServlet {

	static Logger log = Logger.getLogger(MiniServlet.class);

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {		
		doIt(request, response, "GET");
	}
		
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doIt(request, response, "POST");
	}
	
	public void init(ServletConfig config) throws ServletException { 
		super.init(config);
		//String relativeWebPath = "/WEB-INF/static/file1.ext";
		String absoluteDiskPath = getServletContext().getRealPath(".");
		Props.set("cwd",absoluteDiskPath);
		Jugile.print("==== cwd: " + absoluteDiskPath);
		Timer t = new Timer();
		log.info("initializing servlet");
		Cycle.setCtxPath(config.getServletName());
		log.info(" servlet ctxpath: " + Cycle.getCtxPath());
		Cycle.appInit();
		log.info("servlet initialized ms: " + t.stop());
	}
	
	public void doIt(HttpServletRequest req, HttpServletResponse resp, String meth) throws ServletException, IOException {
		req.setCharacterEncoding("UTF-8");
		Cycle c = new Cycle();
		c.setHttpReq(req);
		c.setHttpResp(resp);
		c.ipaddress = req.getLocalAddr();
		c.hostname = req.getServerName();
		c.port = ""+req.getServerPort();
		c.remoteIp = req.getRemoteAddr();
		Request myreq = new Request();

		Enumeration enu = req.getHeaderNames();
		while (enu.hasMoreElements()) {
			String name = (String)enu.nextElement();
			myreq.setHeader(name, req.getHeader(name));
		}
		if (myreq.isMultipart()) {
			BufferedInputStream bis = new BufferedInputStream(req.getInputStream()); 
			myreq.parseMultipart(bis);
		} else {
			if ("POST".equals(meth)) {
				// read body
				BufferedReader reader = req.getReader();  
				char[] buf = new char[8 * 1024]; // 8 KB char buffer  
				int len;
				StringWriter sw = new StringWriter();
				while ((len = reader.read(buf, 0, buf.length)) != -1) {
					sw.write(buf, 0, len);
					//body.append(buf);
				}
				myreq.decodeParms(sw.toString());
				sw.close();
			}
			if ("GET".equals(meth)) {
				enu = req.getParameterNames();
				while (enu.hasMoreElements()) {
					String name = (String)enu.nextElement();
					myreq.setParam(name, req.getParameter(name));
				}
			}
		}
		
		String uri = req.getRequestURI();
		String ctxpath = req.getContextPath() + req.getServletPath();
		uri = uri.replaceFirst(ctxpath, "");
		//myreq.setCtxPath(ctxpath);
		myreq.setURI(uri);
		myreq.setMethod(meth);

		SessionStore ss = null;
		if (!Props.isStateless()) ss = new SessionStore(req);
		Response r = c.serve(myreq, ss);
		if (r == null) throw new ServletException("null response form controller");
		if (r.mimeType != null) resp.setContentType(r.mimeType);
		
		// redirects
		if (Cycle.HTTP_TEMP_REDIRECT.equals(r.status) ||
				Cycle.HTTP_REDIRECT.equals(r.status)) {
		    resp.getWriter();
		    if (Cycle.HTTP_TEMP_REDIRECT.equals(r.status)) 
		    	resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
		    if (Cycle.HTTP_REDIRECT.equals(r.status)) 
		    	resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
		    resp.setHeader("Location", r.header.getProperty("Location"));
		    resp.setContentType("text/html");
		    return;			
		}
		
	    if (Cycle.HTTP_NOTFOUND.equals(r.status))
	    	resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
	    if (Cycle.HTTP_INTERNALERROR.equals(r.status))
	    	resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
	    if (Cycle.HTTP_FORBIDDEN.equals(r.status))
	    	resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
	    if (Cycle.HTTP_BADREQUEST.equals(r.status))
	    	resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
	    if (Cycle.HTTP_NOTIMPLEMENTED.equals(r.status))
	    	resp.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED);
		
		ServletOutputStream out = resp.getOutputStream();
		if ( r.data != null ) {
			byte[] buff = new byte[2048];
			while (true) {
				int read = r.data.read( buff, 0, 2048 );
				if (read <= 0) break;
				out.write( buff, 0, read );
			}
		}

		//out.write(r.getData());
	}

	public class SessionStore implements IStore {
		private HttpServletRequest req;
		public SessionStore(HttpServletRequest req) { 
			this.req = req;
		}
		
		public Object get(String key) { return getStore().get(key);	}
		public void put(String key, Object value) { getStore().put(key, value);	}
		private Map<String,Object> getStore() {
			Map<String,Object> store = (Map<String,Object>)req.getSession().getAttribute("store");
			if (store == null) {
				store = new HashMap<String,Object>();
				req.getSession().setAttribute("store", store);
			}
			return store;
		}		
	}
	
	
}
